﻿
// lunwenDlg.cpp: 实现文件
//

#include "stdafx.h"
#include "lunwen.h"
#include "lunwenDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

int ClunwenDlg::sjj_number_int = 0;
int ClunwenDlg::class_count_int = 1;
int ClunwenDlg::show_hang_shu = 0;
bool ClunwenDlg::oooook = false;
vector<ClassPeople> ClunwenDlg::shujuji;
vector<ClassPeople> ClunwenDlg::shujujifuben;

#pragma region CAboutDlg 对话框

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()

#pragma endregion

// ClunwenDlg 对话框

ClunwenDlg::ClunwenDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_LUNWEN_DIALOG, pParent)
{
	show_hang_shu = 1;
	m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON1);
}

void ClunwenDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_EDIT1_NIAN, nian);
	DDX_Control(pDX, IDC_EDIT2_YUE, yue);
	DDX_Control(pDX, IDC_EDIT3_RI, ri);
	DDX_Control(pDX, IDC_EDIT4_SHI, shi);
	DDX_Control(pDX, IDC_EDIT5_NUMBER, shu_ju_ji_number);
	DDX_Control(pDX, IDC_EDIT6_LEI_COUNT, class_count);
	DDX_Control(pDX, IDC_STATIC_NIAN_ZHU, nian_zhu);
	DDX_Control(pDX, IDC_STATIC_YUE_ZHU, yue_zhu);
	DDX_Control(pDX, IDC_STATIC_RI_ZHU, ri_zhu);
	DDX_Control(pDX, IDC_STATIC_SHI_ZHU, shi_zhu);
	DDX_Control(pDX, IDC_STATIC_WU_XING_NIAN, wu_xing_nian);
	DDX_Control(pDX, IDC_STATIC_WU_XING_YUE, wu_xing_yue);
	DDX_Control(pDX, IDC_STATIC_WU_XING_RI, wu_xing_ri);
	DDX_Control(pDX, IDC_STATIC_WU_XING_SHI, wu_xing_shi);
	DDX_Control(pDX, IDC_STATIC_BA_ZI, ba_zi);
	DDX_Control(pDX, IDC_STATIC_BEI_ZHU, bei_zhu);
	DDX_Control(pDX, IDC_STATIC_MU, mu);
	DDX_Control(pDX, IDC_STATIC_HUO, huo);
	DDX_Control(pDX, IDC_STATIC_TU, tu);
	DDX_Control(pDX, IDC_STATIC_JIN, jin);
	DDX_Control(pDX, IDC_STATIC_SHUI, shui);
	DDX_Control(pDX, IDC_LIST2_XIAN_SHI, list);
}

BEGIN_MESSAGE_MAP(ClunwenDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON1_JIAN_CE, &ClunwenDlg::OnBnClickedButton1JianCe)
	ON_BN_CLICKED(IDC_BUTTON2_SHU_JU_JI, &ClunwenDlg::OnBnClickedButton2ShuJuJi)
	ON_BN_CLICKED(IDC_BUTTON1_NIAN, &ClunwenDlg::OnBnClickedButton1Nian)
	ON_BN_CLICKED(IDC_BUTTON2_YUE, &ClunwenDlg::OnBnClickedButton2Yue)
	ON_BN_CLICKED(IDC_BUTTON3_RI, &ClunwenDlg::OnBnClickedButton3Ri)
	ON_BN_CLICKED(IDC_BUTTON4_SHI, &ClunwenDlg::OnBnClickedButton4Shi)
	ON_MESSAGE(WM_SHOW, OnShow)
END_MESSAGE_MAP()


#pragma region ClunwenDlg 消息处理程序

// ClunwenDlg 消息处理程序

BOOL ClunwenDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时，框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码

	return TRUE;  // 除非将焦点设置到控件，否则返回 TRUE
}

void ClunwenDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮，则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序，
//  这将由框架自动完成。

void ClunwenDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR ClunwenDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

#pragma endregion 

LRESULT ClunwenDlg::OnShow(WPARAM wParam, LPARAM lParam)
{
	//打印类
	//1.在每个类开始之前，写上第几类
	//  需要变量x
	//2.从副本里第一个数组开始，他肯定是某个树的树根，然后层次遍历
	//3.如果此对象的 ID 大于数据集的总数，那不输出，跳过；
	//  反之，将他的“ID”、“年月”、“五行”输出；
	//4.

	for (int i = 0; i < shujujifuben.size(); i++)//i代表类
	{
		//输出第几个类
		char c9[6] = { 0 };
		itoa(i + 1, c9, 10);
		CString di_ji_lei = c9;
		di_ji_lei = "第 " + di_ji_lei + " 类：";
		list.InsertItem(show_hang_shu++, di_ji_lei);

		//队列：遍历树
		queue<int> Q;//每一个类，一个队列
		int pClassPeople = shujujifuben[i].GetID();//拿ID当指针
		Q.push(pClassPeople);
		while (!Q.empty())
		{
			pClassPeople = Q.front();//取队首
			Q.pop();//删队首
			
			int pClassPeople_ID = pClassPeople; //pClassPeople 本来是ID号，但保险起见，在这里再找一个副本
			if (pClassPeople_ID <= sjj_number_int)//输出原数据：pClassPeople <= sjj_number_int 说明是原数据
			{
				//ID号
				char c99[6] = { 0 };
				itoa(pClassPeople_ID, c99, 10);
				CString zhegedeidhao = c99;

				//年
				int x88 = shujuji[pClassPeople_ID - 1].GetNian();
				char c88[6] = { 0 };
				itoa(x88, c88, 10);
				CString zhegedenian = c88;

				//月
				int x77 = shujuji[pClassPeople_ID - 1].GetYue();
				char c77[6] = { 0 };
				itoa(x77, c77, 10);
				CString zhegedeyue = c77;

				//五行：暂无
				
				//显示
				CString cs10086 = "对象 " + zhegedeidhao + "：" + zhegedenian + "." + zhegedeyue + " [" + "五行" + "]" + "\n";
				list.InsertItem(show_hang_shu++, cs10086);
			}

			if (shujuji[pClassPeople_ID - 1].GetZuo() != 0)//加入左
				Q.push(shujuji[pClassPeople_ID - 1].GetZuo());
			if (shujuji[pClassPeople_ID - 1].GetYou() != 0)//加入右
				Q.push(shujuji[pClassPeople_ID - 1].GetYou());
		}

		//类间分隔
		di_ji_lei = "\n\n\n\n\n";
		list.InsertItem(show_hang_shu++, di_ji_lei);
		UpdateData(FALSE);
	}
	return LRESULT();
}

#pragma region 按钮

void ClunwenDlg::OnBnClickedButton1JianCe()
{
	// TODO: 在此添加控件通知处理程序代码

	//定义一个变量：人
	People ren;

	//获取年
	CString nian_cstr;
	nian.GetWindowTextA(nian_cstr);
	string nian_str = (LPCSTR)nian_cstr;
	//赋：年干
	ren.SetNianGan(nian_str);
	//赋：年支
	ren.SetNianZhi(nian_str);

	//获取月
	CString yue_cstr;
	yue.GetWindowTextA(yue_cstr);
	string yue_str = (LPCSTR)yue_cstr;
	//赋：月干
	ren.SetYueGan(yue_str);
	//赋：月支
	ren.SetYueZhi(yue_str);

	//获取日
	CString ri_cstr;
	ri.GetWindowTextA(ri_cstr);
	string ri_str = (LPCSTR)ri_cstr;
	//赋：日干
	ren.SetRiGan(ri_str);
	//赋：日支
	ren.SetRiZhi(ri_str);

	//获取时
	CString shi_cstr;
	shi.GetWindowTextA(shi_cstr);
	string shi_str = (LPCSTR)shi_cstr;
	//赋：时干
	ren.SetShiGan(shi_str);
	//赋：时支
	ren.SetShiZhi(shi_str);

	//赋：四柱
	ren.SetNianZhu();
	ren.SetYueZhu();
	ren.SetRiZhu();
	ren.SetShiZhu();

	//赋：八字
	ren.SetBaZi();

	//赋：五行
	ren.SetWuXing();

	//赋：备注
	ren.SetBeiZhu();

	//获：年柱
	string nian_zhu_str = ren.GetNianZhu();
	CString nian_zhu_cstr = nian_zhu_str.c_str();
	nian_zhu.SetWindowTextA(nian_zhu_cstr);

	//获：月柱
	string yue_zhu_str = ren.GetYueZhu();
	CString yue_zhu_cstr = yue_zhu_str.c_str();
	yue_zhu.SetWindowTextA(yue_zhu_cstr);

	//获：日柱
	string ri_zhu_str = ren.GetRiZhu();
	CString ri_zhu_cstr = ri_zhu_str.c_str();
	ri_zhu.SetWindowTextA(ri_zhu_cstr);

	//获：时柱
	string shi_zhu_str = ren.GetShiZhu();
	CString shi_zhu_cstr = shi_zhu_str.c_str();
	shi_zhu.SetWindowTextA(shi_zhu_cstr);

	//获：五行·年
	string wu_xing_nian_str = ren.GetWuXingNian();
	CString wu_xing_nian_cstr = wu_xing_nian_str.c_str();
	wu_xing_nian.SetWindowTextA(wu_xing_nian_cstr);

	//获：五行·月
	string wu_xing_yue_str = ren.GetWuXingYue();
	CString wu_xing_yue_cstr = wu_xing_yue_str.c_str();
	wu_xing_yue.SetWindowTextA(wu_xing_yue_cstr);

	//获：五行·日
	string wu_xing_ri_str = ren.GetWuXingRi();
	CString wu_xing_ri_cstr = wu_xing_ri_str.c_str();
	wu_xing_ri.SetWindowTextA(wu_xing_ri_cstr);

	//获：五行·时
	string wu_xing_shi_str = ren.GetWuXingShi();
	CString wu_xing_shi_cstr = wu_xing_shi_str.c_str();
	wu_xing_shi.SetWindowTextA(wu_xing_shi_cstr);

	//获：八字
	string ba_zi_str = ren.GetBaZi();
	CString ba_zi_cstr = ba_zi_str.c_str();
	ba_zi.SetWindowTextA(ba_zi_cstr);

	//获：备注
	string bei_zhu_str = ren.GetBeiZhu();
	CString bei_zhu_cstr = bei_zhu_str.c_str();
	bei_zhu.SetWindowTextA(bei_zhu_cstr);

	//获：五行·木
	int mu_int = ren.GetMu();
	char mu_c[5] = { 0 };
	itoa(mu_int, mu_c, 10);
	CString mu_cstr = mu_c;
	mu.SetWindowTextA(mu_cstr);

	//获：五行·火
	int huo_int = ren.GetHuo();
	char huo_c[5] = { 0 };
	itoa(huo_int, huo_c, 10);
	CString huo_cstr = huo_c;
	huo.SetWindowTextA(huo_cstr);

	//获：五行·土
	int tu_int = ren.GetTu();
	char tu_c[5] = { 0 };
	itoa(tu_int, tu_c, 10);
	CString tu_cstr = tu_c;
	tu.SetWindowTextA(tu_cstr);

	//获：五行·金
	int jin_int = ren.GetJin();
	char jin_c[5] = { 0 };
	itoa(jin_int, jin_c, 10);
	CString jin_cstr = jin_c;
	jin.SetWindowTextA(jin_cstr);

	//获：五行·水
	int shui_int = ren.GetShui();
	char shui_c[5] = { 0 };
	itoa(shui_int, shui_c, 10);
	CString shui_cstr = shui_c;
	shui.SetWindowTextA(shui_cstr);
}

void ClunwenDlg::OnBnClickedButton2ShuJuJi()
{
	// TODO: 在此添加控件通知处理程序代码

	if (oooook == true)//线程在跑
	{
		AfxMessageBox("等着！");
		return;
	}

	//获取数据集数量
	CString sjj_number_cstr;
	shu_ju_ji_number.GetWindowTextA(sjj_number_cstr);
	sjj_number_int = atoi(sjj_number_cstr);

	//获取分类数
	CString cc_cstr;
	class_count.GetWindowTextA(cc_cstr);
	class_count_int = atoi(cc_cstr);

	//开线程
	hThread = AfxBeginThread(ThreadFenLei, 0);
}

#pragma endregion

#pragma region 提示按钮

void ClunwenDlg::OnBnClickedButton1Nian()
{
	// TODO: 在此添加控件通知处理程序代码
	AfxMessageBox("示例：2020");
}


void ClunwenDlg::OnBnClickedButton2Yue()
{
	// TODO: 在此添加控件通知处理程序代码
	AfxMessageBox("示例：1");
}


void ClunwenDlg::OnBnClickedButton3Ri()
{
	// TODO: 在此添加控件通知处理程序代码
	AfxMessageBox("示例：2020.1.1");
}


void ClunwenDlg::OnBnClickedButton4Shi()
{
	// TODO: 在此添加控件通知处理程序代码
	AfxMessageBox("示例：0:00");
}

#pragma endregion


UINT ClunwenDlg::ThreadFenLei(LPVOID pParam)
{
	//改状态
	oooook = true;

	//一些整型变量
	int csysgs = sjj_number_int;//初始元素个数
	int zzflsm = class_count_int;//最终分类数目
	if (zzflsm <= 0)
		zzflsm = 1;
	int ldidh = 0;//类的ID号

#pragma region 生成元素集
	//加随机种子
	Common::SuiJiZhong();
	//生成基本元素的类,并放入vector
	for (int i = 0; i < csysgs; i++)
	{
		ClassPeople cp;
		int sjn = Common::SuiJiNian();
		int sjy = Common::SuiJiYue();
		string sjrg = Common::SuiJiRiGan();
		string sjrz = Common::SuiJiRiZhi();
		string sjsg = Common::SuiJiShiGan();
		string sjsz = Common::SuiJiShiZhi();
		cp.SetID(++ldidh);
		cp.SetNian(sjn);
		cp.SetYue(sjy);
		string sjng = Common::GetNianGan(sjn);
		string sjnz = Common::GetNianZhi(sjn);
		string sjyg = Common::GetYueGan(sjn, sjy);
		string sjyz = Common::GetYueZhi(sjy);
		string bbbzzz = sjng + sjnz + "  " + sjyg + sjyz + "  " + sjrg + sjrz + "  " + sjsg + sjsz;
		cp.SetBaZi(bbbzzz);
		float wwwxxx[5] = { 0 };//用作SetWuXing的参数
		for (int j = 0; j < 8; j++)//填充参数
		{
			int t = 5;
			string jie_shou_wu_xing = "";//接收五行，用于判断
			switch (j)
			{
			case 0:jie_shou_wu_xing = Common::QiuWuXingGan(sjng); break;
			case 1:jie_shou_wu_xing = Common::QiuWuXingZhi(sjnz); break;
			case 2:jie_shou_wu_xing = Common::QiuWuXingGan(sjyg); break;
			case 3:jie_shou_wu_xing = Common::QiuWuXingZhi(sjyz); break;
			case 4:jie_shou_wu_xing = Common::QiuWuXingGan(sjrg); break;
			case 5:jie_shou_wu_xing = Common::QiuWuXingZhi(sjrz); break;
			case 6:jie_shou_wu_xing = Common::QiuWuXingGan(sjsg); break;
			case 7:jie_shou_wu_xing = Common::QiuWuXingZhi(sjsz); break;
			default:
				break;
			}
			if (jie_shou_wu_xing == "木")
				t = 0;
			if (jie_shou_wu_xing == "火")
				t = 1;
			if (jie_shou_wu_xing == "土")
				t = 2;
			if (jie_shou_wu_xing == "金")
				t = 3;
			if (jie_shou_wu_xing == "水")
				t = 4;
			wwwxxx[t]++;
		}
		cp.SetWuXing(wwwxxx);
		shujuji.push_back(cp);//将此对象放入数组
	}
#pragma endregion

	//为副本赋值
	shujujifuben = shujuji;//这不不知道为什么错了

	//现在每一个元素是一个类，我们准备将其聚类
	while (1)//一直聚类，直到vector的size只剩下指定分的类的数量时，跳出循环
	{
		//分类数目符合要求
		if (shujujifuben.size() <= zzflsm)
			break;

#pragma region 计算最短距离,得出:zuo you
		//辅助变量
		float min_distance = 0;//余弦相似度：0最远，1最近
		int zuo = 0, you = 1;//用来记录距离最近的两个类的下标，也就是被删的两个类的下标，初始为0、1，代表第1、2个。

		//计算任意两个类的距离
		for (int i = 0; i < shujujifuben.size(); i++)//
			for (int j = i + 1; j < shujujifuben.size(); j++)//
			{
				float distance = Common::CalculateDistance(shujujifuben[i].GetWuXing(), shujujifuben[j].GetWuXing());
				if (distance > min_distance)//距离越大的越近
				{
					min_distance = distance;
					zuo = i;
					you = j;
				}
			}
#pragma endregion

		//知道了距离最近的两个下标值
		//接下来生成一个新类，左右指针指向那两个类，注意：我要指向的是shujuji里面的，不是shujujifuben的，并且下标的确定不用zuo、you，而要用他们的ID
		//创建的新类应加入到两个shujuji中
		//再将shujujifuben中的两个类删掉，用的下标是zuo、you

		//建一个对象
		ClassPeople cp;
		cp.SetID(++ldidh);
		float cuowu1[5] = { 0 };
		float* cuowu11 = Common::CalculateWuXing(shujujifuben[zuo].GetWuXing(), shujujifuben[zuo].GetContain(), shujujifuben[you].GetWuXing(), shujujifuben[you].GetContain());
		memcpy(cuowu1, cuowu11, 5 * sizeof(float));
		cp.SetWuXing(cuowu1);
		cp.SetContain(shujujifuben[zuo].GetContain(), shujujifuben[you].GetContain());
		cp.SetZuo(shujujifuben[zuo].GetID());
		cp.SetYou(shujujifuben[you].GetID());

		//将新类加入到两个数据集中,并为指针赋值
		shujuji.push_back(cp);
		shujujifuben.push_back(cp);

		//从fuben里删除最近的两个
		shujujifuben.erase(shujujifuben.begin() + zuo);
		shujujifuben.erase(shujujifuben.begin() + you - 1);
	}

	oooook = false;
	AfxMessageBox("分类结束！");

	AfxGetMainWnd()->PostMessageA(WM_SHOW, 0, 0);//去显示
	return 0;
}

